/*
	Written By Pradipna Nepal
	www.pradsprojects.com

	Copyright (C) 2012 Prads Projects
	Please read COPYING.txt included along with this source code for more detail.
	If not included, see http://www.gnu.org/licenses/
*/

#include "libIdentifierTable.h"

void IdentifierTable::createIdentTable(vector<TokenModule> *modules, const FuncTable *funcTable,
									   vector<IdentTable> *tOut) {
	IdentEntry entry;
	IdentTable identTable;

	entry.initialValue = string();
	for (unsigned int i = 0; i < modules->size(); ++i) {
		entry.index = 0;
		for (unsigned int li = 0; li < (*modules)[i].lines.size(); ++li) {
			switch ((*modules)[i].lines[li].lineType) {
				case TL_STRUCT:
					while (li < (*modules)[i].lines.size()) {
						if ((*modules)[i].lines[li].lineType == TL_CLOSE_SCOPE) break;
						++li;
					}
					break;
				case TL_VAR_DECLARE:
				case TL_CONST_DECLARE:
				case TL_CONST_STRING_DECLARE:
				case TL_STRUCT_DECLARE:
				case TL_IMAGE_DECLARE:
					entry.type = (*modules)[i].lines[li].tokens[0].getValue();
					entry.name = (*modules)[i].lines[li].tokens[1].getValue();
					if ((*modules)[i].lines[li].tokens[2].getDescription()
								== OPERATOR_ASSIGN) {
						if ((*modules)[i].lines[li].lineType == TL_VAR_DECLARE) {
							(*modules)[i].lines[li].tokens.erase((*modules)[i].lines[li].tokens.begin());
							(*modules)[i].lines[li].lineType = TL_ASSIGNMENT;
						} else {
							entry.initialValue = (*modules)[i].lines[li].tokens[3].getValue();
						}
					}
					if ((*modules)[i].lines[li].tokens[2].getToken() == TOKEN_OPENSQUAREBRACKET) {
						entry.size = atoi((*modules)[i].lines[li].tokens[3].getValue().c_str()) * 2;
					} else {
						if ((*modules)[i].lines[li].lineType == TL_CONST_STRING_DECLARE)
							entry.size = entry.initialValue.size() + 1;
						else if ((*modules)[i].lines[li].lineType == TL_IMAGE_DECLARE)
							entry.size = (atoi((*modules)[i].lines[li].tokens[5].getValue().c_str()) << 16) | atoi((*modules)[i].lines[li].tokens[7].getValue().c_str());
						else
							entry.size = 2;
					}
					identTable.insert(IdentTable::value_type(fnvHash(entry.name.c_str(), entry.name.size()), 
							entry));
					if ((*modules)[i].lines[li].lineType == TL_IMAGE_DECLARE)
						entry.index += ((entry.size >> 17) * (entry.size & 0xFFFF));
					else
						entry.index += entry.size;
					entry.initialValue = string();
					break;
				case TL_FUNTION_DECLARE:
					{
						entry.initialValue = "0";
						entry.size = 1;

						pair<FuncTable::const_iterator, FuncTable::const_iterator> rangeIt;
						
						rangeIt = funcTable->equal_range(fnvHash((*modules)[i].name.c_str(), 
							(*modules)[i].name.size()));
						for (FuncTable::const_iterator it = rangeIt.first; it != rangeIt.second; ++it) {
							if ((*modules)[i].name == it->second.name) {
								for (unsigned int ai = 0; ai < it->second.arguments.size(); ++ai) {
									entry.name = it->second.arguments[ai].name;
									entry.type = it->second.arguments[ai].type;
									identTable.insert(IdentTable::value_type(fnvHash(entry.name.c_str(), entry.name.size()),
										entry));
									entry.index += 2;
								}
							}
						}
					}
			}
		}
		tOut->push_back(identTable);
		identTable.clear();
	}
}